package com.eagle.component.db.mybatisplus;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.ITypeConvert;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.eagle.util.text.StringUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * 说明:
 * 创建时间:2019/12/17
 *
 * @author 姚建星
 * @since
 */
public final class DaoGenerator {
	private AutoGenerator autoGenerator;
	private String projectPath;
	private String outPutDir;
	private String moduleName;
	private StringBuilder stringBuilder;
	private GlobalConfig globalConfig;
	private StrategyConfig strategy;
	private DataSourceConfig dataSourceConfig;
	private PackageConfig packageConfig;
	private InjectionConfig cfg;
	private TemplateConfig templateConfig;


	/**
	 * 指定模板引擎
	 *
	 * @param templateEngine
	 * @return
	 */
	public static DaoGenerator newGenerator(AbstractTemplateEngine templateEngine) {
		AutoGenerator autoGenerator = new AutoGenerator();
		autoGenerator.setTemplateEngine(templateEngine);
		return getDaoGenerator(autoGenerator);
	}

	/**
	 * 使用默认模板引擎创建
	 *
	 * @return
	 */
	public static DaoGenerator newGenerator() {
		AutoGenerator autoGenerator = new AutoGenerator();
		autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
		return getDaoGenerator(autoGenerator);
	}

	public DaoGenerator and() {
		return this;
	}

	/**
	 * @return
	 */
	public DaoGenerator globalConfig() {
		globalConfig = new GlobalConfig();
		globalConfig.setOpen(false);
		this.autoGenerator.setGlobalConfig(globalConfig);
		return this;
	}

	public DaoGenerator outputDir(String outPutDir) {
		this.setOutPutDir(outPutDir);
		String outputDir = this.projectPath + outPutDir + "/src/main/java";
		stringBuilder.append("输出路径:").append(outputDir).append("\r\n");
		this.globalConfig.setOutputDir(outputDir);
		return this;
	}

	public DaoGenerator author(String author) {
		stringBuilder.append("作者:").append(author).append("\r\n");
		this.globalConfig.setAuthor(author);
		return this;
	}

	public DaoGenerator dataSourceConfig() {
		dataSourceConfig = new DataSourceConfig();
		dataSourceConfig.setTypeConvert((new MySqlTypeConvert() {
			@Override
			public DbColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
				String t = fieldType.toLowerCase();
				if (t.contains("char")) {
					return DbColumnType.STRING;
				} else if (t.contains("bigint")) {
					return DbColumnType.LONG;
				} else if (t.contains("tinyint(1)")) {
					return DbColumnType.BOOLEAN;
				} else if (t.contains("int")) {
					return DbColumnType.INTEGER;
				} else if (t.contains("text")) {
					return DbColumnType.STRING;
				} else if (t.contains("bit")) {
					return DbColumnType.BOOLEAN;
				} else if (t.contains("decimal")) {
					return DbColumnType.LONG;
				} else if (t.contains("clob")) {
					return DbColumnType.CLOB;
				} else if (t.contains("blob")) {
					return DbColumnType.BLOB;
				} else if (t.contains("binary")) {
					return DbColumnType.BYTE_ARRAY;
				} else if (t.contains("float")) {
					return DbColumnType.FLOAT;
				} else if (t.contains("double")) {
					return DbColumnType.DOUBLE;
				} else if (!t.contains("json") && !t.contains("enum")) {
					if (t.contains("date") || t.contains("time") || t.contains("year")) {
						byte var5;
						switch(globalConfig.getDateType()) {
							case ONLY_DATE:
								return DbColumnType.DATE;
							case SQL_PACK:
								var5 = -1;
								switch(t.hashCode()) {
									case 3076014:
										if (t.equals("date")) {
											var5 = 0;
										}
										break;
									case 3560141:
										if (t.equals("time")) {
											var5 = 1;
										}
										break;
									case 3704893:
										if (t.equals("year")) {
											var5 = 2;
										}
								}
								
								switch(var5) {
									case 0:
										return DbColumnType.DATE_SQL;
									case 1:
										return DbColumnType.TIME;
									case 2:
										return DbColumnType.DATE_SQL;
									default:
										return DbColumnType.TIMESTAMP;
								}
							case TIME_PACK:
								var5 = -1;
								switch(t.hashCode()) {
									case 3076014:
										if (t.equals("date")) {
											var5 = 0;
										}
										break;
									case 3560141:
										if (t.equals("time")) {
											var5 = 1;
										}
										break;
									case 3704893:
										if (t.equals("year")) {
											var5 = 2;
										}
								}
								
								switch(var5) {
									case 0:
										return DbColumnType.LOCAL_DATE;
									case 1:
										return DbColumnType.LOCAL_TIME;
									case 2:
										return DbColumnType.YEAR;
									default:
										return DbColumnType.LOCAL_DATE_TIME;
								}
						}
					}
					return DbColumnType.STRING;
				} else {
					return DbColumnType.STRING;
				}
			}
		}));
		this.autoGenerator.setDataSource(dataSourceConfig);
		return this;
	}

	public DaoGenerator url(String url) {
		stringBuilder.append("数据源URL:").append(url).append("\r\n");
		this.dataSourceConfig.setUrl(url);
		return this;
	}

	public DaoGenerator driverName(String driverName) {
		stringBuilder.append("数据源驱动:").append(driverName).append("\r\n");
		this.dataSourceConfig.setDriverName(driverName);
		return this;
	}

	public DaoGenerator username(String username) {
		stringBuilder.append("数据源用户名:").append(username).append("\r\n");
		this.dataSourceConfig.setUsername(username);
		return this;
	}

	public DaoGenerator password(String password) {
		stringBuilder.append("数据源密码:").append(password).append("\r\n");
		dataSourceConfig.setPassword(password);
		return this;
	}
	public DaoGenerator typeConvert(ITypeConvert typeConvert){
		dataSourceConfig.setTypeConvert(typeConvert);
		return this;
	}

	public DaoGenerator packageConfig() {
		packageConfig = new PackageConfig();
		this.autoGenerator.setPackageInfo(packageConfig);
		return this;
	}

	public DaoGenerator moduleName(String moduleName, String packageName) {
		if (StringUtil.isNotBlank(moduleName)) {
			this.moduleName = moduleName;
		} else {
			this.moduleName = scanner("模块名");
		}
		stringBuilder.append("包路径:").append(packageName).append(".").append(this.moduleName).append("\r\n");
		packageConfig.setModuleName(this.moduleName);
		packageConfig.setParent(packageName);
		InjectionConfig cfg = new InjectionConfig() {
			@Override
			public void initMap() {
				// to do nothing
			}
		};

		String templatePath = "/templates/mapper.xml.ftl";

		// 自定义输出配置
		List<FileOutConfig> focList = new ArrayList<>();
		// 自定义配置会被优先输出
		focList.add(new FileOutConfig(templatePath) {
			@Override
			public String outputFile(TableInfo tableInfo) {
				// 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
				return projectPath + outPutDir+ "/src/main/resources/mapper/"+ tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
			}
		});
		cfg.setFileOutConfigList(focList);
		this.autoGenerator.setCfg(cfg);
		return this;
	}

	public DaoGenerator strategyConfig() {
		strategy = new StrategyConfig();
		strategy.setNaming(NamingStrategy.underline_to_camel);
		strategy.setColumnNaming(NamingStrategy.underline_to_camel);
		strategy.setEntityLombokModel(true);
		strategy.setRestControllerStyle(true);
		// 公共父类
		strategy.setSuperControllerClass("com.eagle.web.controller.EagleBaseController");
		strategy.setControllerMappingHyphenStyle(true);
		strategy.setTablePrefix(getModuleName() + "_"); 
		this.autoGenerator.setStrategy(strategy);
		return this;
	}

	public DaoGenerator tableName(String tableName) {
		if (StringUtil.isNotBlank(tableName)) {
			strategy.setInclude(tableName.split(","));
		} else {
			strategy.setInclude(scanner("表名，多个英文逗号分割").split(","));
		}
		return this;
	}

	public void execute() {
		TemplateConfig templateConfig = new TemplateConfig();
		templateConfig.setXml(null);
		this.autoGenerator.setTemplate(templateConfig);
		System.out.println(stringBuilder.toString());
		this.autoGenerator.execute();
	}

	/**
	 * <p>
	 * 读取控制台内容
	 * </p>
	 */
	private String scanner(String tip) {
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入" + tip + "：");
		if (scanner.hasNext()) {
			String ipt = scanner.next();
			if (StringUtils.isNotEmpty(ipt)) {
				return ipt;
			}
		}
		System.out.println("请输入正确的" + tip + "！");
		return scanner(tip);
	}

	private static DaoGenerator getDaoGenerator(AutoGenerator autoGenerator) {
		DaoGenerator daoGenerator = new DaoGenerator();
		daoGenerator.setAutoGenerator(autoGenerator);
		daoGenerator.setProjectPath(System.getProperty("user.dir"));
		daoGenerator.setStringBuilder(new StringBuilder());
		return daoGenerator;
	}

	public AutoGenerator getAutoGenerator() {
		return autoGenerator;
	}

	public void setAutoGenerator(AutoGenerator autoGenerator) {
		this.autoGenerator = autoGenerator;
	}

	public String getProjectPath() {
		return projectPath;
	}

	public void setProjectPath(String projectPath) {
		this.projectPath = projectPath;
	}

	public String getModuleName() {
		return moduleName;
	}

	public void setModuleName(String moduleName) {
		this.moduleName = moduleName;
	}

	public StringBuilder getStringBuilder() {
		return stringBuilder;
	}

	public void setStringBuilder(StringBuilder stringBuilder) {
		this.stringBuilder = stringBuilder;
	}

	public GlobalConfig getGlobalConfig() {
		return globalConfig;
	}

	public void setGlobalConfig(GlobalConfig globalConfig) {
		this.globalConfig = globalConfig;
	}

	public StrategyConfig getStrategy() {
		return strategy;
	}

	public void setStrategy(StrategyConfig strategy) {
		this.strategy = strategy;
	}

	public DataSourceConfig getDataSourceConfig() {
		return dataSourceConfig;
	}

	public void setDataSourceConfig(DataSourceConfig dataSourceConfig) {
		this.dataSourceConfig = dataSourceConfig;
	}

	public PackageConfig getPackageConfig() {
		return packageConfig;
	}

	public void setPackageConfig(PackageConfig packageConfig) {
		this.packageConfig = packageConfig;
	}

	public InjectionConfig getCfg() {
		return cfg;
	}

	public void setCfg(InjectionConfig cfg) {
		this.cfg = cfg;
	}

	public TemplateConfig getTemplateConfig() {
		return templateConfig;
	}

	public void setTemplateConfig(TemplateConfig templateConfig) {
		this.templateConfig = templateConfig;
	}

	public String getOutPutDir() {
		return outPutDir;
	}

	public void setOutPutDir(String outPutDir) {
		this.outPutDir = outPutDir;
	}
}